home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Mania 6
/
MacMania 6.toast
/
/
Tools&Utilities
/
EnterAct Stuff
/
Drag_on Modules
/
hAWK example progs
/
$FuncTree
< prev
next >
Wrap
Text File
|
1994-01-26
|
7KB
|
379 lines
# $FuncTree : on a per-file basis, print a list of function definitions
# as encountered, and for each defined function print a list of functions
# called by the defined function.
# -this was written to prototype EnterAct's function call/caller tree indexer.
BEGIN {
init_lexer();
first_time = 1
}
FNR == 1 {
z = split(ARGV[1], names, ":")
filename = names[z];
curlyCount = 0
numCalls = 0
numDefs = 0
current_function = ""
could_be_definition = 0
toktype = ILLEGAL
line = $0
if (first_time != 1)
init_arrays();
collect_functions();
print_names();
first_time = 0
}
##END { print_names(); }
function init_arrays( k)
{
for (k in func_not_printed)
delete func_not_printed[k];
for (k in func_defs)
delete func_defs[k];
for (k in func_tree)
delete func_tree[k];
}
function collect_functions( type)
{
advance();
while (toktype != EOF)
{
if (toktype == NAME)
{
type = lookup(tok) # see hAWK User’s Manual 2114 or so
if (type == 4)
{
##funcs[tok]++
record_function()
}
}
else if (toktype == "{")
{
++curlyCount;
if (could_be_definition == 1 && curlyCount == 1)
{
func_defs[++numDefs] = current_function
func_not_printed[current_function] = 1
func_tree[current_function, ++numCalls] = "T";
}
}
else if (toktype == "}")
{
--curlyCount;
if (curlyCount == 0) # outside a function
{
current_function = "";
could_be_definition = 0;
}
}
else if (curlyCount == 0 && could_be_definition == 1 && toktype == ";")
could_be_definition = 0;
advance();
}
}
function record_function()
{
if (curlyCount == 0) # top level - NOTE could be a prototype for the func
{
current_function = tok
numCalls = 0
could_be_definition = 1
}
else if (current_function != "") # inside a function(?)
{
func_tree[current_function, ++numCalls] = tok
}
}
# For each function definition in the file, in order of occurrence,
# print a list of called functions, also in order of occurrence.
# Only functions which actually call another function are listed,
# and duplicates are suppressed in the call list.
function print_names( i, j, k, fn)
{
for (i = 1; i <= numDefs; ++i)
{
fn = func_defs[i]
if (((fn, 1) in func_tree) \
&& func_not_printed[fn]) # not a spurious mention, not done yet
{
func_not_printed[fn] = 0
for (k in seen)
delete seen[k];
print fn, ":"
j = 2; # 1 is just to show function is defined
while ((fn, j) in func_tree)
{
tok = func_tree[fn, j]
if (!(tok in seen))
{
print "\t", tok
seen[tok] = 1
}
++j;
}
}
}
}
function init_lexer()
{
NAME = 256
STRING = 257
CHAR_CONSTANT = 258
NUMBER = 259
KEY = 260
BITASSIGNOP = 261
ASSIGNOP = 262
LEX_OR = 263
LEX_AND = 264
RELOP = 265
SHIFT = 266
INCREMENT = 267
DECREMENT = 268
POINTER = 269
OTHER = 270
EOF = 271
ILLEGAL = 272
C_KEY["..."] = 1
C_KEY["asm"] = 1
C_KEY["auto"] = 1
C_KEY["break"] = 1
C_KEY["case"] = 1
C_KEY["char"] = 1
C_KEY["class"] = 1
C_KEY["const"] = 1
C_KEY["continue"] = 1
C_KEY["default"] = 1
C_KEY["delete"] = 1
C_KEY["do"] = 1
C_KEY["double"] = 1
C_KEY["else"] = 1
C_KEY["enum"] = 1
C_KEY["extern"] = 1
C_KEY["float"] = 1
C_KEY["for"] = 1
C_KEY["goto"] = 1
C_KEY["if"] = 1
C_KEY["int"] = 1
C_KEY["long"] = 1
C_KEY["new"] = 1
C_KEY["Pascal"] = 1
C_KEY["pascal"] = 1
C_KEY["register"] = 1
C_KEY["return"] = 1
C_KEY["short"] = 1
C_KEY["signed"] = 1
C_KEY["sizeof"] = 1
C_KEY["static"] = 1
C_KEY["struct"] = 1
C_KEY["switch"] = 1
C_KEY["typedef"] = 1
C_KEY["union"] = 1
C_KEY["unsigned"] = 1
C_KEY["virtual"] = 1
C_KEY["void"] = 1
C_KEY["volatile"] = 1
C_KEY["while"] = 1
}
function advance()
{
if (toktype == EOF) return
if (tok == "." || tok == "->") #member coming, not a local
{
if (match(line, /^[A-Za-z_](\w|_)*/))
{
tok = substr(line, 1, RLENGTH)
line = substr(line, RLENGTH+1)
toktype = OTHER
return
}
else
error("missing member name")
}
toktype = ILLEGAL
skip_comments_etc()
if (toktype == EOF || toktype == STRING || toktype == CHAR_CONSTANT)
return
if (match(line, /^[A-Za-z_](\w|_)*/) ||
match(line, /^\.\.\./)) #name or key - note "..." treated as key.
{
tok = substr(line, 1, RLENGTH)
line = substr(line, RLENGTH+1)
if (tok in C_KEY)
toktype = KEY
else
toktype = NAME
return
}
if (match(line, /^([0-9]+\.?[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)?[fFlL]?/) ||
match(line, /^0[0-7]+(u|U)?(l|L)?/) ||
match(line, /^0(x|X)[0-9a-fA-F]+(u|U)?(l|L)?/)) #float or int
toktype = NUMBER;
else if (match(line, /^(<<=|>>=|&=|\^=|\|=)/)) #bit assign
toktype = BITASSIGNOP
else if (match(line, /^(\+=|-=|\*=|\/=|%=)/)) #assign, inc
toktype = ASSIGNOP
else if (match(line, /^\|\|/))
toktype = LEX_OR
else if (match(line, /^&&/))
toktype = LEX_AND
else if (match(line, /^(<=|==|!=|>=)/)) #relational
toktype = RELOP
else if (match(line, /^(<<|>>)/)) #shift
toktype = SHIFT
else if (match(line, /^\+\+/))
toktype = INCREMENT
else if (match(line, /^--/))
toktype = DECREMENT
else if (match(line, /^->/))
toktype = POINTER
else if (match(line, /^./)) #everything else
{
#TO DO trap illegal tokens, eg "@"
toktype = substr(line,1,1)
}
else
error("Unexpected empty line")
tok = substr(line, 1, RLENGTH)
line = substr(line, RLENGTH+1)
}
function skip_comments_etc()
{
do
{
sub(/^[ \t]+/, "", line) #remove leading blanks and tabs
sub(/^\/\/.*/, "", line) #remove C++ comments
while (match(line, /^"|^\/\*|^'/))
{
if (match(line, /^"/))
{
GetString()
return
}
else if (match(line, /^'/))
{
GetCharConstant()
return
}
else
SkipComment()
sub(/^[ \t]+/, "", line)
sub(/^\/\/.*/, "", line)
}
} while (length(line) == 0 && getline line > 0);
if (length(line) == 0)
toktype = EOF
}
function GetString( len, c, i, temp, esc)
{
len = length(line)
i = 2;
for (esc = 0; i <= len; ++i)
{
c = substr(line, i, 1)
if (c == "\"")
{
if (esc == 0 || esc%2 == 0)
{
tok = temp substr(line,1,i)
line = substr(line, i+1)
toktype = STRING
return;
}
else
esc = 0
}
else if (c == "\\")
{
if (i == len) #end of line, string continued
{
temp = temp substr(line,1,len-1)
if (getline line <= 0)
error("unterminated string")
else
{
esc = 0
i = 0
len = length(line)
if (len == 0)
error("unterminated string")
}
}
else
++esc
}
else
esc = 0
}
error("unterminated string")
}
function GetCharConstant( len, c, i, esc)
{
len = length(line)
i = 2;
toktype = CHAR_CONSTANT
for (esc = 0; i <= len; ++i)
{
c = substr(line, i, 1)
if (c == "'")
{
if (esc == 0 || esc%2 == 0)
{
tok = substr(line,1,i)
line = substr(line, i+1)
return;
}
else
esc = 0
}
else if (c == "\\")
++esc
else
esc = 0
}
error("unterminated char constant")
}
function SkipComment( len, c, i)
{
i = 3;
do
{
for (len = length(line); i <= len; ++i)
{
c = substr(line, i, 2)
if (c == "*/")
{
line = substr(line, i+2)
return;
}
}
i = 1;
} while (getline line > 0);
error("unterminated comment")
}
function error(s)
{
print "Error:", s
print "Location:", filename, NR
print "Current Line:", line
print "Current token", tok
print "Current toktype:", toktype
exit 1
}